Function.RegisterNamespace("Test.System.Script.Attributes");

[Fixture]
Test.System.Script.Attributes.AttributeParser=function(){
    [Fixture]
    function Parse(){
        [Fact]
        function FindsSingleAttributeInArrayBeforeNamedFunction(){
            var testScript="[Attribute]\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute]);function TestFunction(){\n\talert('Testing')\n}";
         
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }
        [Fact]
        function FindsMultipleAttributesInArrayBeforeNamedFunction(){
            var testScript="[Attribute1,Attribute2]\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute1,Attribute2]);function TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }
        [Fact]
        function FindsMultipleAttributeArraysBeforeNamedFunction(){
            var testScript="[Attribute1]\n[Attribute2]\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute1],[Attribute2]);function TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }
        [Fact]
        function FindsMultipleAttributesinMultipleArraysBeforeNamedFunction(){
            var testScript="[Attribute1, Attribute2]\n[Attribute3, Attribute4]\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute1, Attribute2],[Attribute3, Attribute4]);function TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsAttributeFollowedBySingleLineCommentBeforeNamedFunction(){
            var testScript="[Attribute]\n//This is a comment\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute]\n//This is a comment\n);function TestFunction(){\n\talert('Testing')\n}";
         
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);        
        }

        [Fact]
        function FindsAttributeFollowedByMultipleSingleLineCommentsBeforeNamedFunction(){
            var testScript="[Attribute]\n//This is a comment\n//This is another\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute]\n//This is a comment\n//This is another\n);function TestFunction(){\n\talert('Testing')\n}";
         
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact,Skip("Need real parse tree for this.")]
        function FindsAttributeFollowedBySingleLineBlockCommentBeforeNamedFunction(){
            var testScript="[Attribute]\n/*This is a comment*/\n\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute]);function TestFunction(){\n\talert('Testing')\n}";
         
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);        
        }

        [Fact,Skip("Need real parse tree for this.")]
        function FindsAttributeFollowedByMultiLineBlockCommentBeforeNamedFunction(){
            var testScript="[Attribute]\n/*This is a comment\nIt has multiple lines\nSimilar to JSDoc, perhaps*/\n\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute]);function TestFunction(){\n\talert('Testing')\n}";
         
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);        
        }

        [Fact,Skip("Need real parse tree for this.")]
        function FindsAttributeWithArrayParameter(){
            var testScript="[Attribute([1,2,3,4])]\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute(1,2,3,4)]);function TestFunction(){\n\talert('Testing')\n}";
         
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsAttributeWithObjectParameter(){
            var testScript="[Attribute({one:1,two:2,three:3,four:4})]\nfunction TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute({one:1,two:2,three:3,four:4})]);function TestFunction(){\n\talert('Testing')\n}";
         
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function GeneratesNameForAnonymousFunction(){
            var testScript="[Attribute]\nfunction(){\n\talert('Testing')\n}";
            
            var target=new System.Script.Attributes.AttributeParser().Parse(testScript);
            var actual=target.match(/^var anonymous_\d*/);
            
            Assert.NotNull(actual);
        }
        
        [Fact]
        function FindsSingleAttributeInArrayBeforeAnonymousFunction(){
            var testScript="[Attribute]\nfunction(){\n\talert('Testing')\n}";
            var targetExpected="var {0}=new System.Script.Attributes.DecoratedFunction({0},\"{0}\",[Attribute]);function {0}(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            var targetName=actual.match(/^var (anonymous_\d*)/)[1];
            var expected=String.Format(targetExpected,targetName);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsMultipleAttributesInArrayBeforeAnonymousFunction(){
            var testScript="[Attribute1,Attribute2]\nfunction (){\n\talert('Testing')\n}";
            var targetExpected="var {0}=new System.Script.Attributes.DecoratedFunction({0},\"{0}\",[Attribute1,Attribute2]);function {0}(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            var targetName=actual.match(/^var (anonymous_\d*)/)[1];
            var expected=String.Format(targetExpected,targetName);
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function FindsMultipleAttributeArraysBeforeAnonymousFunction(){
            var testScript="[Attribute1]\n[Attribute2]\nfunction\n(){\n\talert('Testing')\n}";
            var targetExpected="var {0}=new System.Script.Attributes.DecoratedFunction({0},\"{0}\",[Attribute1],[Attribute2]);function {0}(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            var targetName=actual.match(/^var (anonymous_\d*)/)[1];
            var expected=String.Format(targetExpected,targetName);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsMultipleAttributesinMultipleArraysBeforeAnonymousFunction(){
            var testScript="[Attribute1, Attribute2]\n[Attribute3, Attribute4]\nfunction(){\n\talert('Testing')\n}";
            var targetExpected="var {0}=new System.Script.Attributes.DecoratedFunction({0},\"{0}\",[Attribute1, Attribute2],[Attribute3, Attribute4]);function {0}(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            var targetName=actual.match(/^var (anonymous_\d*)/)[1];
            var expected=String.Format(targetExpected,targetName);
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function FindsNamedFunctionAssignedToNewVariable(){
            var testScript="[Attribute1]\nvar TestVariable=function TestFunction(){\n\talert('Testing')\n}";
            var expected="var TestVariable=TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute1]);function TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsNamedFunctionAssignedToExistingVariable(){
            var testScript="[Attribute1]\nTestVariable=function TestFunction(){\n\talert('Testing')\n}";
            var expected="TestVariable=TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute1]);function TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsNamedFunctionAssignedToNameSpacedVariable(){
            var testScript="[Attribute1]\nTestNameSpace.TestClass.TestVariable=function TestFunction(){\n\talert('Testing')\n}";
            var expected="TestNameSpace.TestClass.TestVariable=TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute1]);function TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function FindsNamedFunctionAssignedToVariableContainingUnderScores(){
            var testScript="[Attribute1]\nTest_Variable=function TestFunction(){\n\talert('Testing')\n}";
            var expected="Test_Variable=TestFunction=new System.Script.Attributes.DecoratedFunction(TestFunction,\"TestFunction\",[Attribute1]);function TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsUnassignedAnonymousFunction(){
            var testScript="[Attribute1]\nfunction(){\n\talert('Testing')\n}";
            var targetExpected="var {0}=new System.Script.Attributes.DecoratedFunction({0},\"{0}\",[Attribute1]);function {0}(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            var targetName=actual.match(/^var (anonymous_\d*)/)[1];
            var expected=String.Format(targetExpected,targetName);
            
            Assert.Equal(expected,actual);
        }


        [Fact]
        function FindsAnonymousFunctionAssignedToNewVariable(){
            var testScript="[Attribute1]\nvar TestVariable=function(){\n\talert('Testing')\n}";
            var expected="var TestVariable=new System.Script.Attributes.DecoratedFunction(TestVariable,\"TestVariable\",[Attribute1]);function TestVariable(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsAnonymousFunctionAssignedToExistingVariable(){
            var testScript="[Attribute1]\nTestVariable=function(){\n\talert('Testing')\n}";
            var expected="TestVariable=new System.Script.Attributes.DecoratedFunction(TestVariable,\"TestVariable\",[Attribute1]);function TestVariable(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function FindsAnonymousFunctionAssignedToNameSpacedVariableAndReplacesPeriodsWithUnderScores(){
            var testScript="[Attribute1]\nTestNameSpace.TestClass.TestVariable=function(){\n\talert('Testing')\n}";
            var expected="TestNameSpace.TestClass.TestVariable=new System.Script.Attributes.DecoratedFunction(TestNameSpace_TestClass_TestVariable,\"TestNameSpace.TestClass.TestVariable\",[Attribute1]);function TestNameSpace_TestClass_TestVariable(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(testScript);
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function IgnoresFunctionsWithDuplicateAttributeClustersAcrossVariableAssignment(){
            var expected="[Attribute1]\nvar TestVariable=\n[Attribute2]\nfunction TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(expected);
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function IgnoresAttributesBetweenAttributesAndFunctionDeclaration(){
            var expected="[Attribute]"+"function TestFunction(){alert('Testing')}";

            var actual=new System.Script.Attributes.AttributeParser().Parse(expected);
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function DoesNotConvertCrossLineArrayAssignment(){
            var expected="var array=\n[ArrayValue1]\nfunction TestFunction(){\n\talert('Testing')\n}";
            
            var actual=new System.Script.Attributes.AttributeParser().Parse(expected);
            
            Assert.Equal(expected,actual);
        }
    }
}